// 继承
function Fu(){
    this.poperty=true;
};
Fu.prototype.say()=()=>{
    console.log(this.property);
};
function Zi(){
    this.sub_property=false;
};
// 继承使得子类对象具有父类对象的属性和方法

// 1.原型链
Zi.prototype=new Fu();
// 子类原型对象被父类构造函数进行实例化
// 使得子类原型对象[[prototype]]指向父类的原型对象，形成原型链，通过原型链访问，形式上类似于获得父类原型对象中的方法和属性
// 在父类构造函数实例化子类原型对象时，子类原型对象会获得父类构造函数中定义的属性和方法
// 此过程还可以进行向父类构造函数传参，以获得对应的属性值或方法参数
let zi1=new Zi();
// 子类构造函数实例化一个对象，其[[prototype]]指向子类的原型对象，从而可以访问其上的属性和方法
// 在实例化后，实例获得子类构造函数上的属性和方法，此过程可以传参，以获得对应属性值和方法参数
// 继承自父类对象的属性值不能通过传参进行修改
zi1 instanceof Fu;
// 构造函数与实例之间是实例化关系
// 通过原型链继承，其原型链上构造函数，均与实例具有实例化关系
Fu.prototype.isPrototypeOf(zi1);
// 原型对象与实例之间是原型关系
// 通过原型链继承，其原型链上的原型对象，均与实例具有原型关系
zi1.constructor
// 通过继承后实例化的对象，该属性指向最终的父类构造函数

//原型链问题
// (1)需要对子类原型对象进行修改时，需在继承操作后进行(继承操作会覆盖此前操作)
// (2)当采用字面量形式修改原型对象时
// 父类原型对象的constructor会指向Object
// 子类原型对象会导致重写而使得原型链失效
// (3)原型链采用原型模式，其在父类构造函数定义的属性在继承后会出现在子类的原型对象上
// 故当使用引用类型值继承时，对不同实例操作引用值，会导致其原型链上的初始值修改
// (4)构造函数参数传递
// 在继承操作时传递构造函数参数，会导致子类该属性不具有可修改性


// 2.盗用构造函数
function Zi1(a){
    Fu.call(this,a);
    // a为传递参数
}
// 在子类构造函数中,运行父类构造函数,使得子类实例可以访问父类构造函数中的方法和属性,但不能访问父类原型对象上的方法和属性
// 实际上为构造模式,仅能继承来自构造函数中的属性和方法,不具有原型链
// 在定义子类构造函数与运行父类构造函数时,可以设置相关参数来进行参数传递
// 故在子类实例化时,进行传参可以传递到父类构造函数


// 3.组合式继承
// 将原型链和盗用构造函数两种方式进行组合
// (1)对于方法,定义在父类原型对象上,采用原型链继承
// (2)对于需要修改的属性,定义在父类构造函数上,采用盗用构造函数继承
// (3)对于不需要修改的属性,定义在父类原型对象上,采用原型链继承
// (4)对于引用类型属性,定义在父类构造函数上,采用盗用构造函数继承

// 盗用构造函数:实例修改的属性,引用值属性
// 原型链:方法,不修改的属性



// 4.原型式继承
// 借用函数来创建原型链，仅关注对象而忽略对象的构造函数（引用类型）
function object(o){
    function F(){
        // 创建一个子类的临时构造函数
        F.prototype=o;
        // o为父类，将子类的原型对象赋值为o
    }
    return F();
    // 返回子类的临时构造函数的一个实例
}
// 在不调用对象的构造函数条件下，实现两个对象间的继承关系(实质同样创建原型链)，会具有原型模式的特点
Object.create(obj,{});
// 第一个参数为父类的实例对象，第二个参数为需要新添加的属性，为属性描述对象
// 返回值为一个继承父类的子类实例对象


// 5.寄生式继承
// 思路为利用函数，在某一返回对象的基础上，进行对象增强功能，再将增强后的对象返回
function jisheng(){
    let new_obj=object(o);
    // 对某一返回的对象进行操作
    new_obj.sayName=()=>{
        console.log(this.name);
    }
    // 增强功能
    return new_obj;
    // 返回增强的对象
}


// 6.组合寄生式继承
// 组合式继承，由于同时进行盗用构造函数与原型链
// 实际上会调用两次父类构造函数
Zi.prototype=new Fu();
// 第一次调用，继承父类原型对象同时，会在子类原型对象上继承到父类构造函数的属性和方法
let Zi2=new Zi();
// 第二次调用，子类构造函数内会再次调用父类构造函数，会覆盖第一次调用时，继承自父类构造函数的属性和方法

// 缺点：
// （1）实际上调用了两次构造函数，性能弱
// （2）会进行不必要操作（继承原型对象时，同时在子类原型对象上具有父类构造函数的属性和方法）

// 组合寄生式继承：
// 对原型链继承进行修改，采用原型寄生式继承，即不关注构造函数，仅关注实例对象本身
// 在子类原型对象上，仅继承父类原型对象，不涉及父类的构造函数
function yuanxingjisheng(o){
    let proto=object(o);
    // 创建变量用于存储子类的原型对象
    // 对某一返回的对象进行操作
    // 其原型对象进行重写，constructor属性发生了改变
    proto.constructor=Fu;
    // 修改该属性，使其指向对应的构造函数
    Zi.prototype=proto;
    // 对象增强
}
yuanxingjisheng(Fu.prototype);
// 在需要继承时，调用该函数
// 采用原型寄生式继承，仅继承其原型对象
// 避免了实例化时对构造函数的不必要继承
